// 继承：通过结构体的嵌套实现
package oop

import "fmt"

// 定义父结构体
type Person struct {
	Name string
	Age  int
}

// 定义父结构体的方法
func (p *Person) SayHello() {
	fmt.Printf("hello, %s\n", p.Name)
}

// ============================================================================
// 使用匿名结构体嵌套定义子结构体
// 相当于继承Person，Person中的属性和方法都可以使用
type Student struct {
	Person // 通过匿名结构体的形式不常用。
	school string
}

// ============================================================================
// 定义测试函数
func TestExtendsStu() {
	var stu = &Student{ // 可以直接初始化。stu是指针类型
		school: "HUST",
	}
	stu.Name = "hy.bai" // 等价:stu.Person.Name = "hy.bai"
	// stu可以直接"."属性进行赋值。
	stu.Age = 18
	fmt.Printf("stu的类型:%T,值是%v\n", stu, stu) // 打印:stu的类型:*oop.Student,值是&{{hy.bai 18} HUST}
	stu.SayHello()
}

// ============================================================================

// 常用的方式是：使用指针内嵌
// 能用指针就用指针。使用指针类型结构体进行嵌套
type Teacher struct {
	Person *Person // 嵌套结构体需要初始化
	School string
}

func TestExtendsTea() {
	// 结构体嵌套
	stu := &Teacher{
		// 方式1:初始化Person这个内嵌的结构体
		Person: &Person{},
		School: "jx",
	}

	// 方式2:初始化Person这个内嵌的结构体
	// p := &Person{} // 注：通过指针进行结构体嵌套时，需要初始化
	// p.Name = "ybxb"
	// p.Age = 18
	// stu.Person = p

	// fmt.Println(stu)               // 打印：&{0xc000008060 jx}
	fmt.Printf("%T, %v\n", stu, stu)                                               // 打印：*oop.Teacher, &{0xc000008048 jx}
	fmt.Printf("属性值分别是：%v, %v, %v\n", stu.Person.Name, stu.Person.Age, stu.School) // 打印：属性值分别是：ybxb, 18, jx
	stu.Person.SayHello()
}
